<?php
// app/Http/Middleware/ApiStatistics.php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
use App\Utils\RedisUtil;
use App\Http\Middleware\Base;
class ApiStatistics extends Base
{
    public function handle(Request $request, Closure $next)
    {
        $startTime = microtime(true);
        
        $response = $next($request);
        
        $endTime = microtime(true);
        $executionTime = round(($endTime - $startTime) * 1000, 2);

        $this->logRequest($request, $response, $executionTime);
        
        return $response;
    }
    
    private function logRequest(Request $request, $response, $executionTime)
    {
        $logData = [
            'ip'             => $request->ip(),
            'method'         => $request->method(),
            'url'            => $request->fullUrl(),
            'user_agent'     => $request->userAgent(),
            'status_code'    => $response->getStatusCode(),
            'execution_time' => $executionTime,
            'timestamp'      => now()->toDateTimeString(),
            'user_id'        => auth()->id() ?? 'guest',
        ];

        // 记录到日志文件 - 美化格式
        $this->writeFormattedLog($logData);
        
        // 存储统计信息
        $this->storeStatistics($logData);
    }
    
    private function writeFormattedLog($logData)
    {
        // 方法1：JSON 美化格式
        $formattedLog = json_encode($logData, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
        
        Log::channel('api')->info("API Request\n" . $formattedLog);
        
        // 方法2：键值对格式（如果需要更易读的格式）
        /*
        $logMessage = sprintf(
            "API Request Details:\n" .
            "├─ IP: %s\n" .
            "├─ Method: %s\n" .
            "├─ URL: %s\n" .
            "├─ User Agent: %s\n" .
            "├─ Status Code: %d\n" .
            "├─ Execution Time: %.2fms\n" .
            "├─ Timestamp: %s\n" .
            "└─ User ID: %s",
            $logData['ip'],
            $logData['method'],
            $logData['url'],
            $logData['user_agent'],
            $logData['status_code'],
            $logData['execution_time'],
            $logData['timestamp'],
            $logData['user_id']
        );
        
        Log::channel('api')->info($logMessage);
        */
    }
    
    private function storeStatistics($logData)
    {
        try {
            $today = now()->format('Y-m-d');
            $hour = now()->format('Y-m-d-H');
            
            // 日统计
            $dailyKey = "api:statistics:daily:{$today}";
            $this->updateStatistics($dailyKey, $logData);
            
            // 小时统计
            $hourlyKey = "api:statistics:hourly:{$hour}";
            $this->updateStatistics($hourlyKey, $logData);
            
            // IP 统计
            $this->updateIpStatistics($logData);
            
            // 用户统计（如果有用户ID）
            if ($logData['user_id'] !== 'guest') {
                $this->updateUserStatistics($logData);
            }
            
        } catch (\Exception $e) {
            Log::warning('Redis not available for statistics, using fallback: ' . $e->getMessage());
            $this->storeStatisticsFallback($logData);
        }
    }
    
    private function updateStatistics($key, $logData)
    {
        // 获取现有统计
        $stats = RedisUtil::getData($key) ?? [
            'total_requests'        => 0,
            'total_execution_time'  => 0,
            'status_codes'          => [],
            'methods'               => [],
            'avg_response_time'     => 0
        ];
        
        // 更新统计
        $stats['total_requests']++;
        $stats['total_execution_time'] += $logData['execution_time'];
        $stats['avg_response_time'] = round($stats['total_execution_time'] / $stats['total_requests'], 2);
        
        // 状态码统计
        $statusCode = $logData['status_code'];
        $stats['status_codes'][$statusCode] = ($stats['status_codes'][$statusCode] ?? 0) + 1;
        
        // 方法统计
        $method = $logData['method'];
        $stats['methods'][$method] = ($stats['methods'][$method] ?? 0) + 1;
        
        // 保存统计，设置过期时间
        $expire = strpos($key, 'hourly:') !== false ? 3600 * 24 : 86400 * 30;
        RedisUtil::setData($key, $stats, $expire);
    }
    
    private function updateIpStatistics($logData)
    {
        $ip = $logData['ip'];
        $today = now()->format('Y-m-d');
        
        $ipKey = "api:statistics:ip:{$today}:{$ip}";
        $ipStats = RedisUtil::getData($ipKey) ?? [
            'request_count' => 0,
            'last_access'   => now()->toDateTimeString(),
            'user_agent'    => $logData['user_agent'],
            'status_codes'  => []
        ];
        
        $ipStats['request_count']++;
        $ipStats['last_access'] = now()->toDateTimeString();
        
        $statusCode = $logData['status_code'];
        $ipStats['status_codes'][$statusCode] = ($ipStats['status_codes'][$statusCode] ?? 0) + 1;
        
        RedisUtil::setData($ipKey, $ipStats, 86400 * 7);
    }
    
    private function updateUserStatistics($logData)
    {
        $userId = $logData['user_id'];
        $today = now()->format('Y-m-d');
        
        $userKey = "api:statistics:user:{$today}:{$userId}";
        $userStats = RedisUtil::getData($userKey) ?? [
            'request_count'         => 0,
            'last_activity'         => now()->toDateTimeString(),
            'status_codes'          => [],
            'total_execution_time'  => 0
        ];
        
        $userStats['request_count']++;
        $userStats['last_activity'] = now()->toDateTimeString();
        $userStats['total_execution_time'] += $logData['execution_time'];
        
        $statusCode = $logData['status_code'];
        $userStats['status_codes'][$statusCode] = ($userStats['status_codes'][$statusCode] ?? 0) + 1;
        
        RedisUtil::setData($userKey, $userStats, 86400 * 30);
    }
    
    private function storeStatisticsFallback($logData)
    {
        try {
            $statsFile = storage_path('logs/api_statistics.json');
            $today = now()->format('Y-m-d');
            
            if (file_exists($statsFile)) {
                $stats = json_decode(file_get_contents($statsFile), true) ?: [];
            } else {
                $stats = [];
            }
            
            if (!isset($stats[$today])) {
                $stats[$today] = [
                    'total_requests'        => 0,
                    'status_codes'          => [],
                    'methods'               => [],
                    'total_execution_time'  => 0
                ];
            }
            
            // 更新统计
            $stats[$today]['total_requests']++;
            $stats[$today]['total_execution_time'] += $logData['execution_time'];
            
            $statusCode = $logData['status_code'];
            $stats[$today]['status_codes'][$statusCode] = 
                ($stats[$today]['status_codes'][$statusCode] ?? 0) + 1;
                
            $method = $logData['method'];
            $stats[$today]['methods'][$method] = 
                ($stats[$today]['methods'][$method] ?? 0) + 1;
            
            file_put_contents($statsFile, json_encode($stats, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE));
            
        } catch (\Exception $e) {
            Log::error('Failed to store API statistics fallback: ' . $e->getMessage());
        }
    }
    
    /**
     * 获取统计数据的辅助方法（可在控制器中调用）
     */
    public static function getDailyStatistics($date = null)
    {
        $date = $date ?: now()->format('Y-m-d');
        $key = "api:statistics:daily:{$date}";
        return RedisUtil::getData($key);
    }
    
    public static function getHourlyStatistics($hour = null)
    {
        $hour = $hour ?: now()->format('Y-m-d-H');
        $key = "api:statistics:hourly:{$hour}";
        return RedisUtil::getData($key);
    }
    
    public static function getIpStatistics($ip, $date = null)
    {
        $date = $date ?: now()->format('Y-m-d');
        $key = "api:statistics:ip:{$date}:{$ip}";
        return RedisUtil::getData($key);
    }
}
